CMU-5380 - 2o semestre/2017 - T4

Integração sequencial e paralela, identificação de processamentos e ordem de aplicação.

Arthur Tofani - 3339712

Especificação do trabalho:

  • O objetivo deste trabalho e demonstrar e descrever a diferença entre um processamento paralelo e serial realizado com 2 módulos processadores atuando sobre um som de referência.
  • Escolha dois módulos de processamentos (M1 e M2). Os módulos podem implementar a mesma função ou diferentes funções mas devem ser da mesma categoria, isto é, devem realizar processamento de dinâmica ou espectral.

Criação de filtros

Usaremos, para este experimento, dois filtros como módulos de processamento M1 e M2, sendo M1 um filtro PB com frequência de corte em 400Hz e m2 um PA com frequência de corte em 2400Hz. Utilizaremos a versão streaming da biblioteca Essentia. Abaixo, para fins de referência, podemos escutar o áudio original e resultado do processamento do áudio original por cada um dos filtros, de modo independente:

In [174]:
import essentia
from essentia.streaming import *
import IPython
filename = 'cello-double.wav'
In [175]:
# áudio original
IPython.display.Audio(filename)
Out[175]:
In [176]:
# Audio original após processamento de filtro PB (M1)
IPython.display.Audio('lpf.wav')
Out[176]:
In [177]:
# Audio original após processamento de filtro PA (M2)
IPython.display.Audio('hpf.wav')
Out[177]:

Aplicação dos filtros em série:

Agora, aplicaremos os dois filtros em série, processando inicialmente pelo filtro PB e depois pelo PA:

In [178]:
loader = essentia.streaming.MonoLoader(filename=filename)
lpf_serial_hpf_filename = 'lpf_serial_hpf.wav'

writer = MonoWriter(filename=lpf_serial_hpf_filename)
lpf = LowPass(cutoffFrequency=400)
hpf = HighPass(cutoffFrequency=2400)


# processa o fluxo de audio pelos módulos criados EM SÉRIE
loader.audio >> lpf.signal >> hpf.signal >> writer.audio
essentia.run(loader)

# reproduz o áudio resultante
IPython.display.Audio(lpf_serial_hpf_filename)
Out[178]:

Também criaremos uma segunda versão em série, passando inicialmente por PA e depois por PB:

In [179]:
loader = essentia.streaming.MonoLoader(filename=filename)
lpf_serial_hpf_filename = 'lpf_serial_hpf2.wav'

writer = MonoWriter(filename=lpf_serial_hpf_filename)
lpf = LowPass(cutoffFrequency=400)
hpf = HighPass(cutoffFrequency=2400)


# processa o fluxo de audio pelos módulos criados EM SÉRIE
loader.audio >> hpf.signal >> lpf.signal >> writer.audio
essentia.run(loader)

# reproduz o áudio resultante
IPython.display.Audio(lpf_serial_hpf_filename)
Out[179]:

Aplicação dos filtros em paralelo:

Agora, processaremos o sinal em paralelo nos filtros PA e PB, e depois adicionamos o resultados em um mesmo arquivo:

In [180]:
loader = essentia.streaming.MonoLoader(filename=filename)
lpf_parallel_hpf_filename = 'lpf_parallel_hpf.wav'

writer = MonoWriter(filename=lpf_parallel_hpf_filename)
lpf = LowPass(cutoffFrequency=400)
hpf = HighPass(cutoffFrequency=2400)
pool = essentia.Pool()

# processa o fluxo de audio pelos módulos criados EM SÉRIE
loader.audio >> lpf.signal >> (pool, 'lpf')
loader.audio >> hpf.signal >> (pool, 'hpf')
essentia.run(loader)

# mixa os dois áudios e cria o arquivo final
vector_input = VectorInput(pool['lpf'] + pool['hpf'])
vector_input.data >> writer.audio
essentia.run(vector_input)

# reproduz o áudio resultante
IPython.display.Audio(lpf_parallel_hpf_filename)
Out[180]:

Discussão

Foi escolhida como amostra original uma pequena frase de violoncelo, por haver nela bastante informação em boa parte do espectro, o que nos permite escutar mais claramente o resultado do processamento dos filtros. Para fins de melhor comparação, foram extraídas previamente amostras do áudio resultante do processamento individual do audio original por cada um dos filtros M1 e M2.

Abaixo, discutiremos o resultado perceptível após o processamento por M1 e M2 dos dois modos diferentes, em série e em paralelo.

Processamento em série:

O resultado perceptível da aplicação dos filtros em série foi muito semelhante entre as duas versões (PA->PB e PB->PA), e ambas bastante diferentes da versão original. Independente da ordem da aplicação dos filtros, as duas versões encontram-se com a mesma 'ausência' nos graves e nos agudos. Faz sentido, considerando o processo de consecutivas atenuações pelo qual o audio original passou.

Processamento em paralelo:

O resultado perceptível é diferente do áudio original e também diferente resultado do processamento em série. De fato, os materiais das bandas graves e agudas não são removidos após a adição dos sinais A e B resultantes do processamento dos filtros, pois o que falta em A ainda está em B e vice-versa. Neste caso, o efeito produzido pelo processamento em paralelo concentra-se nas frequências que estão no centro do espectro, onde deverá haver excitação de faixas de frequências, e não só atenuação das mesmas.

Abaixo foram novamente adicionados os áudios, por praticidade.

In [184]:
IPython.display.Audio(filename)
Out[184]:
In [185]:
IPython.display.Audio('lpf.wav')
Out[185]:
In [186]:
IPython.display.Audio('hpf.wav')
Out[186]:
In [187]:
IPython.display.Audio(lpf_serial_hpf_filename)
Out[187]:
In [188]:
IPython.display.Audio(lpf_parallel_hpf_filename)
Out[188]: